﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NeonMika.Webserver.ClientLibrary
{
    public class Netduino
    {
        private const int nDigitalPins = 14;
        private const int nAnalogPins = 6;
        private int[] pwm = new int[] { 5, 6, 9, 10 };

        private Communicator communicator;

        public ObservableCollection<DigitalPin> DigitalPins { get; private set; }
        public ObservableCollection<AnalogPin> AnalogPins { get; private set; }
        public string IP { get; set; }

        public Netduino()
        {
            DigitalPins = new ObservableCollection<DigitalPin>();
            AnalogPins = new ObservableCollection<AnalogPin>();

            for (int i = 0; i < nDigitalPins; i++)
            {
                if (pwm.Contains(i))
                {

                    DigitalPins.Add(new DigitalPin(i, true, this));
                }
                else
                {
                    DigitalPins.Add(new DigitalPin(i, false, this));
                }
            }

            for (int i = 0; i < nAnalogPins; i++)
                AnalogPins.Add(new AnalogPin(i, this));

            communicator = new Communicator();
        }

        public void UpdateAll()
        {
            if (IP != "")
            {
                UpdateDigitalPins();
                UpdateAnalogPins();
                UpdatePWMPins();
            }
        }

        public string UpdatePWMPins()
        {
            if (IP != "")
            {
                communicator.getAllPWMValues.ClearParameter();
                communicator.getAllPWMValues.Execute(IP);
                Dictionary<string, string> pins = communicator.getAllPWMValues.LastResponseAsDictionary();
                for (int i = 0; i < pins.Count; i++)
                {
                    string keyName = pins.ElementAt(i).Key;
                    int pin = Int32.Parse(keyName.Substring(3, 1));
                    if (keyName.Substring(keyName.IndexOf("_") + 1).StartsWith("p"))
                        DigitalPins[pin].Period = Int32.Parse(pins.ElementAt(i).Value);
                    else
                        DigitalPins[pin].Duration = Int32.Parse(pins.ElementAt(i).Value);
                }
                return communicator.getAllPWMValues.LastResponseAsXDocument().ToString();
            }
            return "";
        }

        public string UpdateDigitalPins()
        {
            if (IP != "")
            {
                communicator.getAllDigitalPinStates.ClearParameter();
                communicator.getAllDigitalPinStates.Execute(IP);
                Dictionary<string, string> pins = communicator.getAllDigitalPinStates.LastResponseAsDictionary();

                for (int i = 0; i < nDigitalPins; i++)
                {
                    DigitalPins[i].Value = Int32.Parse(pins["pin" + i]);
                }
                return communicator.getAllDigitalPinStates.LastResponseAsXDocument().ToString();
            }
            return "";
        }

        public string UpdateAnalogPins()
        {
            if (IP != "")
            {
                communicator.getAllAnalogPinValues.ClearParameter();
                communicator.getAllAnalogPinValues.Execute(IP);
                Dictionary<string, string> pins = communicator.getAllAnalogPinValues.LastResponseAsDictionary();
                for (int i = 0; i < nAnalogPins; i++)
                {
                    AnalogPins[i].Value = Int32.Parse(pins["pin" + i]);
                }
                return communicator.getAllAnalogPinValues.LastResponseAsXDocument().ToString();
            }
            return "";
        }

        public string SwitchPin(int pin)
        {
            if (DigitalPins[pin].IsPWM)
            {
                if (DigitalPins[pin].Duration > 0)
                    return SetPWM(pin, 0, 0);
                else
                    return SetPWM(pin, 20000, 20000);
            }
            else
            {
                if (IP != "")
                {
                    communicator.switchDigitalPin.ClearParameter();
                    communicator.switchDigitalPin.AddParameter("pin", pin);
                    communicator.switchDigitalPin.Execute(IP);
                    Dictionary<string, string> pinXml = communicator.switchDigitalPin.LastResponseAsDictionary();
                    DigitalPins[pin].Value = Int32.Parse(pinXml.ElementAt(0).Value);
                    return communicator.switchDigitalPin.LastResponseAsXDocument().ToString();
                }
                return "";
            }
        }

        public string SetDigitalPin(int pin, bool state)
        {
            if (DigitalPins[pin].IsPWM)
            {
                if (state)
                    return SetPWM(pin, 20000, 20000);
                else
                    return SetPWM(pin, 0, 0);
            }
            else
            {
                if (IP != "")
                {
                    communicator.setDigitalPin.ClearParameter();
                    communicator.setDigitalPin.AddParameter("pin", pin);
                    communicator.setDigitalPin.AddParameter("state", state);
                    communicator.setDigitalPin.Execute(IP);
                    Dictionary<string, string> pinXml = communicator.setDigitalPin.LastResponseAsDictionary();
                    DigitalPins[pin].Value = Int32.Parse(pinXml.ElementAt(0).Value);
                    return communicator.setDigitalPin.LastResponseAsXDocument().ToString();
                }
                return "";
            }
        }

        public string SetPWM(int pin, int duration, int period)
        {
            if (IP != "")
            {
                communicator.setPwm.ClearParameter();
                communicator.setPwm.AddParameter("pin", pin);
                communicator.setPwm.AddParameter("duration", duration);
                communicator.setPwm.AddParameter("period", period);
                communicator.setPwm.Execute(IP);
                Dictionary<string, string> pinXml = communicator.setPwm.LastResponseAsDictionary();

                string value = pinXml.ElementAt(0).Value;
                DigitalPins[pin].Period = Int32.Parse(value.Substring(0, value.IndexOf("/")));
                DigitalPins[pin].Duration = Int32.Parse(value.Substring(value.IndexOf("/") + 1, value.Length - 1 - value.IndexOf("/")));

                return communicator.setPwm.LastResponseAsXDocument().ToString();
            }
            return "";
        }

        public string Echo(string value)
        {
            if (IP != "")
            {
                communicator.echo.ClearParameter();
                communicator.echo.AddParameter("value", value);
                communicator.echo.Execute(IP);
                Dictionary<string, string> echoXml = communicator.echo.LastResponseAsDictionary();
                return communicator.echo.LastResponseAsXDocument().ToString();
            }
            return "";
        }
    }
}
